package vip.bblog.oauth2.config;

import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.http.HttpServletRequest;

/**
 * @author <a href="1396513066@qq.com">Yu Yong</a>
 * @version 1.0
 * @date 2019年03月24日 13:51
 * @desc ResourceServer 资源服务配置
 * @url <a href="https://projects.spring.io/spring-security-oauth/docs/oauth2.html#resource-server-configuration"></a>
 * 该@EnableResourceServer注释添加类型的过滤器OAuth2AuthenticationProcessingFilter自动Spring Security的过滤器链，解析access_token
 * @see org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter
 * 解析后通过DefaultTokenServices，根据access_token和认证服务器配置里的TokenStore(token存储方式)从redis或jwt中解析出用户信息
 * @see org.springframework.security.oauth2.provider.token.DefaultTokenServices
 * 认证中心的@EnableResourceServer和别的微服务里的@EnableResourceServer不同，别的微服务是通过UserInfoTokenServices来获取用户信息的<br>
 * @see org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices
 * @see org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration 入口，一直点到ResourceServerTokenServicesConfiguration
 * 这里面 UserInfoTokenServicesConfiguration 如果不是token认证服务器
 * 它就会注入UserInfoTokenServices到容器，然后 ResourceServerConfiguration 就会把UserInfoTokenServices设置到OAuth2AuthenticationManager中
 * @see ResourceServerSecurityConfigurer 的tokenServices(HttpSecurity http)相关的就可以看到原理了，如果没有ResourceServerTokenServices，它就会
 * 生成DefaultTokenServices
 */
@Configuration
@EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatcher(new AuthorizationRequestedMatcher()).authorizeRequests()
                .antMatchers().permitAll()
                .anyRequest().authenticated();
    }

    /**
     * 判断请求来源中国是否包含oauth2授权信息<br>
     */
    private static class AuthorizationRequestedMatcher implements RequestMatcher {
        @Override
        public boolean matches(HttpServletRequest request) {
            //头部的Authorization值以Bearer开头
            String auth = request.getHeader("Authorization");
            if (auth != null) {
                return auth.startsWith(OAuth2AccessToken.BEARER_TYPE);
            }
            //请求参数中包含access_token参数
            String access_token = request.getParameter(OAuth2AccessToken.ACCESS_TOKEN);
            if (StringUtils.isBlank(access_token)) {
                return false;
            } else {
                return access_token.startsWith(OAuth2AccessToken.BEARER_TYPE);
            }
        }
    }

}
